package trie2;



/**
 * @author Programacion2
 * @version 1.0
 */
public class TLista {
	public TElemento primero;
	
	private int cantidadElementos;
	/**
	 * Constructor por defecto 
	 */
	public TLista () {
		primero = null;
		cantidadElementos = 0;
	}
 
	/**
	 * @return Retorna el Primer elemento de la lista
	 */
	public TElemento obtenerPrimero() {
		return primero;
	}

	/**
	 * @return Elemento colocado al final de la lista
	 */
	public TElemento obtenerUltimo() {
		if (esVacia()) {
			return null;
		}
		TElemento elem = primero;
		while (elem.siguiente != null) {
			elem = elem.siguiente;
		}
		return elem;
	}
	
	/**
	 * Metodo encargado de insertar un elemento en la lista
	 * 
	 * @param unElemento El elemento que queremos insertar
	 * @return true si se pudo insertar
	 */
	
	public boolean insertarAlPrincipio (TElemento unElemento){
		if (unElemento != null) {
			unElemento.siguiente = primero;
			primero = unElemento;
			cantidadElementos++;
			return true;
		}
		return false;
	}
	
	/**
	 * Metodo encargado de insertar un elemento al final de la lista.
	 * 
	 * @param unElemento El elemento que queremos insertar
	 * @return true si se pudo insertar
	 */
	
	public boolean insertarAlFinal (TElemento unElemento) {
		if (unElemento != null) {
			if (esVacia()) {
				primero = unElemento;
			} else {
				TElemento auxiliar = obtenerUltimo();
				auxiliar.siguiente = unElemento;
			}
			cantidadElementos++;
			return true;
		}
		return false;
	}
	
	/**
	 * Metodo encargado de indicar si la lista no contiene elementos.-
	 * 
	 * @return true si la lista no tiene elementos
	 */
	
	public boolean esVacia () {
		return (primero == null);
	}
	
	/**
	 * @param unElemento Elemento que queremos verificar si existe
	 * @return true sii el elemento es parte de la lista
	 */
	public boolean existeElemento(TElemento unElemento) {
		if (unElemento != null) {
			return (buscarEtiqueta(unElemento.etiqueta) != null);
		}
		return false;
	}
	
	/**
	 * @param unaEtiqueta Etiqueta del elemento a localizar
	 * @return el elemento a localizar
	 */
	@SuppressWarnings({ "unchecked" })
	public TElemento buscarEtiqueta(Comparable unaEtiqueta) {
		TElemento elem = primero;
		while (elem != null){
			if (elem.etiqueta.compareTo(unaEtiqueta) == 0) {
				return elem;
			}
			elem = elem.siguiente;
		}
		return null;
	}
	
	/**
	 * @param unElemento Elemento a eliminar
	 * @return true sii se pudo eliminar el elemento
	 */
	public boolean eliminar(TElemento unElemento) {
		if (unElemento != null){
			return eliminarEtiqueta(unElemento.etiqueta);
		}
		return false;
	}
	
	/*********************************** OPERACIONES AVANZADAS DE LA LISTA ********************************/
	
	/**
	 * @param unaEtiqueta Etiqueta del elemento a eliminar
	 * @return true sii se pudo eliminar el elemento
	 */
	@SuppressWarnings({ "unchecked" })
	public boolean eliminarEtiqueta (Comparable unaEtiqueta) {
		if (esVacia()){
			return false;
		} else {
			if (primero.etiqueta.compareTo(unaEtiqueta)==0){
				primero = primero.siguiente;
				cantidadElementos--;
				return true;
			} else {
				return eliminarInterno(primero.siguiente,primero,unaEtiqueta);
			}
		}
	}
	
	@SuppressWarnings({ "unchecked" })
	private boolean eliminarInterno(TElemento elementoActual, TElemento anterior, Comparable etiquetaAEliminar) {
		if (elementoActual==null){
			return false;
		} else {
			if (elementoActual.etiqueta.compareTo(etiquetaAEliminar)==0){ //lo encontre, elimino
				anterior.siguiente = elementoActual.siguiente;
				cantidadElementos--;
				return true;
			} else {
				return eliminarInterno(elementoActual.siguiente,elementoActual,etiquetaAEliminar);
			}
		}
	}
	
	/**
	 * @return Cantidad de elementos de la lista
	 */
	public int obtenerCantidadElementos() {
		return cantidadElementos;
	}

	/**
	 * @param unElemento El elemento que queremos insertar 
	 * @return true sii se pudo insertar 
	 */
	@SuppressWarnings("unchecked")
	public boolean insertarOrdenado(TElemento elementoAInsertar){
		if (esVacia() || (primero.etiqueta.compareTo(elementoAInsertar.etiqueta)> 0)){
			return insertarAlPrincipio(elementoAInsertar);
		} else {
			return insertarOrdenadoInterno(primero, primero.siguiente ,elementoAInsertar);	
		}
	}

	@SuppressWarnings("unchecked")
	private boolean insertarOrdenadoInterno(TElemento anterior, TElemento actual, TElemento elementoAInsertar) {
		if (actual == null){
			//inserto como siguiente del anterior
			anterior.siguiente = elementoAInsertar;
			return true;
		} else {
			int comparacionClaves = actual.etiqueta.compareTo(elementoAInsertar.etiqueta); 
			if (comparacionClaves >= 0){
				elementoAInsertar.siguiente = actual;
				anterior.siguiente = elementoAInsertar;
				return true;
			} else {
				return insertarOrdenadoInterno(actual,actual.siguiente,elementoAInsertar);
			}
		}
	}

	/**
	 * 
	 */
	public void vaciar() {
		primero = null;
		cantidadElementos = 0;
	}
	
	/**
	 * Invierte el contenido de la lista
	 */
	public TLista invertir() {
		TLista listaTemporalInversion = new TLista();
		TElemento elem = primero;
		while (elem != null) {
			TElemento aux = new TElemento(elem.etiqueta, null);
			listaTemporalInversion.insertarAlPrincipio(aux);
			elem = elem.siguiente;
		}
		return listaTemporalInversion;
	}
		
	/**
	 * @param unElemento Elemento cuyo anterior queremos localizar
	 * @return Elemento anterior
	 */
	public TElemento anterior(TElemento unElemento) {
		if (unElemento != null){			
			return anterior(unElemento.etiqueta);
		}
		return null;
	}
	
	/**
	 * @param unaEtiqueta Etiqueta del elemento cuyo anterior queremos localizar
	 * @return Elemento anterior
	 */
	public TElemento anterior(Comparable unaEtiqueta) {
		TElemento anterior = null;
		TElemento actual = primero;
		while(actual != null){
			if (actual.etiqueta.equals(unaEtiqueta)){
				break;
			}
			anterior = actual;
			actual = actual.siguiente;
		}
		return anterior;
	}
	
	
	/**
	 * @return las etiquetas de la lista concatenadas, separadas por el separador definido
	 */
	@SuppressWarnings("unchecked")
	public Comparable[] etiquetasToArray() {
		Comparable[] salida = new Comparable[obtenerCantidadElementos()];
		TElemento elementoActual = primero;
		int posicionActual = 0;
		while(elementoActual != null){
			salida[posicionActual] = elementoActual.etiqueta;
			elementoActual = elementoActual.siguiente;
			posicionActual++;
		}
		return salida;
	}
	
	public String imprimirEtiquetas() {
		StringBuilder salida = new StringBuilder();
		TElemento elementoActual = primero;
		while(elementoActual != null){
			if (salida.length() > 0){
				salida.append("-");
			}
			salida.append(elementoActual.etiqueta);
			elementoActual = elementoActual.siguiente;
		}
		return salida.toString();
	}

	public String toString(){
		return imprimirEtiquetas();
	}
	
	
	public TLista ordenar() {
		TLista listaOrd = new TLista();
		TElemento elem = primero;
		while (elem != null) {
			TElemento aux = new TElemento(elem.etiqueta, null);
			listaOrd.insertarOrdenado(aux);
			elem = elem.siguiente;
		}
		return listaOrd;
	}

	public TElemento quitarPrimero() {
		TElemento elem = primero;
		eliminar(primero);
		return elem;
	}
}
